home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
3D GFX
/
3D GFX.iso
/
amiutils
/
i_l
/
irit5
/
cagd_lib
/
cbsp_aux.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-12-30
|
34KB
|
866 lines
/******************************************************************************
* CBsp-Aux.c - Bspline curve auxilary routines. *
*******************************************************************************
* Written by Gershon Elber, Aug. 90. *
******************************************************************************/
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include "cagd_loc.h"
/*****************************************************************************
* DESCRIPTION: M
* Given a Bspline curve - subdivides it into two sub-curves at the given M
* parametric value. M
* Returns pointer to first curve in a list of two subdivided curves. M
* The subdivision is achieved by inserting (order-1) knot at the given M
* parameter value t and spliting the control polygon and knot vector at that M
* location. M
* *
* PARAMETERS: M
* Crv: To subdivide at parametr value t. M
* t: Parameter value to subdivide Crv at. M
* *
* RETURN VALUE: M
* CagdCrvStruct *: A list of the two subdivided curves. M
* *
* KEYWORDS: M
* BspCrvSubdivAtParam, subdivision, refinement M
*****************************************************************************/
CagdCrvStruct *BspCrvSubdivAtParam(CagdCrvStruct *Crv, CagdRType t)
{
CagdBType
NewCrv = FALSE,
IsNotRational = !CAGD_IS_RATIONAL_CRV(Crv);
int i, j, Len, KVLen, Index1, Index2, Mult,
k = Crv -> Order,
MaxCoord = CAGD_NUM_OF_PT_COORD(Crv -> PType);
CagdRType TMin, TMax, *LOnePts, *ROnePts, *OnePts, *NewKV,
**Pts, **LPts, **RPts;
CagdCrvStruct *LCrv, *RCrv;
BspKnotAlphaCoeffType *A;
if (CAGD_IS_PERIODIC_CRV(Crv)) {
NewCrv = TRUE;
Crv = CnvrtPeriodic2FloatCrv(Crv);
}
Len = Crv -> Length;
KVLen = k + Len;
Index1 = BspKnotLastIndexL(Crv -> KnotVector, KVLen, t);
if (Index1 + 1 < k)
Index1 = k - 1;
Index2 = BspKnotFirstIndexG(Crv -> KnotVector, KVLen, t);
if (Index2 > Len)
Index2 = Len;
Mult = k - 1 - (Index2 - Index1 - 1);
CAGD_DOMAIN_GET_AND_VERIFY_CRV(t, Crv, TMin, TMax);
LCrv = BspCrvNew(Index1 + 1, k, Crv -> PType);
RCrv = BspCrvNew(Len - Index2 + k, k, Crv -> PType);
/* Update the new knot vectors. */
CAGD_GEN_COPY(LCrv -> KnotVector,
Crv -> KnotVector,
sizeof(CagdRType) * (Index1 + 1));
/* Close the knot vector with multiplicity Order: */
for (j = Index1 + 1; j <= Index1 + k; j++)
LCrv -> KnotVector[j] = t;
CAGD_GEN_COPY(&RCrv -> KnotVector[k],
&Crv -> KnotVector[Index2],
sizeof(CagdRType) * (Len + k - Index2));
/* Make sure knot vector starts with multiplicity Order: */
for (j = 0; j < k; j++)
RCrv -> KnotVector[j] = t;
/* Now handle the control polygon refinement. */
Pts = Crv -> Points,
LPts = LCrv -> Points,
RPts = RCrv -> Points;
if (Mult > 0) {
NewKV = IritMalloc(sizeof(CagdRType) * Mult);
for (i = 0; i < Mult; i++)
NewKV[i] = (t == TMax ? t - CAGD_DOMAIN_EPSILON : t);
A = BspKnotEvalAlphaCoefMerge(k, Crv -> KnotVector, Len, NewKV,
Mult);
IritFree((VoidPtr) NewKV);
}
else {
A = BspKnotEvalAlphaCoef(k, Crv -> KnotVector, Len,
Crv -> KnotVector, Len);
}
/* Note that Mult can be negative in cases where original */
/* multiplicity was order or more and we need to compensate */
/* here, since Alpha matrix will be just a unit matrix then. */
Mult = Mult >= 0 ? 0 : -Mult;
/* Blend Crv into LCrv. */
for (j = IsNotRational; j <= MaxCoord; j++) {
LOnePts = LPts[j];
OnePts = Pts[j];
for (i = 0; i < LCrv -> Length; i++, LOnePts++)
CAGD_ALPHA_BLEND(A, i, OnePts, Crv -> Length, LOnePts);
}
/* Blend Crv into RCrv. */
for (j = IsNotRational; j <= MaxCoord; j++) {
ROnePts = RPts[j];
OnePts = Pts[j];
for (i = LCrv -> Length - 1 + Mult;
i < LCrv -> Length + RCrv -> Length - 1 + Mult;
i++, ROnePts++)
CAGD_ALPHA_BLEND(A, i, OnePts, Crv -> Length, ROnePts);
}
BspKnotFreeAlphaCoef(A);
BspKnotMakeRobustKV(RCrv -> KnotVector,
RCrv -> Order + RCrv -> Length);
BspKnotMakeRobustKV(LCrv -> KnotVector,
LCrv -> Order + LCrv -> Length);
LCrv -> Pnext = RCrv;
if (NewCrv)
CagdCrvFree(Crv);
return LCrv;
}
/*****************************************************************************
* DESCRIPTION: M
* Inserts n knot, all with the value t. In no case will the multiplicity of M
* a knot be greater or equal to the curve order. M
* *
* PARAMETERS: M
* Crv: To refine by insertion (upto) n knot of value t. M
* t: Parameter value of new knot to insert. M
* n: Maximum number of times t should be inserted. M
* *
* RETURN VALUE: M
* CagdCrvStruct *: Refined Crv with n knots of value t. M
* *
* KEYWORDS: M
* BspCrvKnotInsertNSame, refinement, subdivision M
*****************************************************************************/
CagdCrvStruct *BspCrvKnotInsertNSame(CagdCrvStruct *Crv, CagdRType t, int n)
{
int i,
CrntMult = BspKnotFindMult(Crv -> KnotVector, Crv -> Order,
Crv -> Length, t),
Mult = MIN(n, Crv -> Order - CrntMult - 1);
CagdCrvStruct *RefinedCrv;
if (Mult > 0) {
CagdRType
*NewKV = (CagdRType *) IritMalloc(sizeof(CagdRType) * Mult);
for (i = 0; i < Mult; i++)
NewKV[i] = t;
RefinedCrv = BspCrvKnotInsertNDiff(Crv, FALSE, NewKV, Mult);
IritFree((VoidPtr) NewKV);
}
else {
RefinedCrv = CagdCrvCopy(Crv);
}
return RefinedCrv;
}
/*****************************************************************************
* DESCRIPTION: M
* Inserts n knot with different values as defined by the vector t. If, M
* however, Replace is TRUE, the knot are simply replacing the current knot M
* vector. M
* *
* PARAMETERS: M
* Crv: To refine by insertion (upto) n knot of value t. M
* Replace: if TRUE, the n knots in t should replace the knot vector M
* of size n of Crv. Sizes must match. If False, n new knots M
* as defined by t will be introduced into Crv. M
* t: New knots to introduce/replace knot vector of Crv. M
* n: Size of t. M
* *
* RETURN VALUE: M
* CagdCrvStruct *: Refined Crv with n new knots. M
* *
* KEYWORDS: M
* BspCrvKnotInsertNDiff, refinement, subdivision M
*****************************************************************************/
CagdCrvStruct *BspCrvKnotInsertNDiff(CagdCrvStruct *Crv,
CagdBType Replace,
CagdRType *t, int n)
{
CagdBType
NewCrv = FALSE,
IsNotRational = !CAGD_IS_RATIONAL_CRV(Crv);
CagdRType *KnotVector;
int Length,
Order = Crv -> Order,
MaxCoord = CAGD_NUM_OF_PT_COORD(Crv -> PType);
CagdCrvStruct *RefinedCrv;
if (CAGD_IS_PERIODIC_CRV(Crv)) {
NewCrv = TRUE;
Crv = CnvrtPeriodic2FloatCrv(Crv);
}
Length = Crv -> Length;
KnotVector = Crv -> KnotVector;
if (Replace) {
int i;
if (Order + Length != n)
CAGD_FATAL_ERROR(CAGD_ERR_NUM_KNOT_MISMATCH);
for (i = 1; i < n; i++)
if (t[i] < t[i - 1])
CAGD_FATAL_ERROR(CAGD_ERR_KNOT_NOT_ORDERED);
RefinedCrv = CagdCrvCopy(Crv);
for (i = 0; i < n; i++)
RefinedCrv -> KnotVector[i] = *t++;
}
else if (n == 0) {
RefinedCrv = CagdCrvCopy(Crv);
}
else {
int i, j, LengthKVt;
BspKnotAlphaCoeffType *A;
CagdRType *MergedKVt, TMin, TMax;
BspCrvDomain(Crv, &TMin, &TMax);
for (i = 1; i < n; i++)
if (t[i] < t[i - 1])
CAGD_FATAL_ERROR(CAGD_ERR_KNOT_NOT_ORDERED);
for (i = 0; i < n; i++)
if (t[i] >= TMax)
t[i] -= CAGD_DOMAIN_EPSILON;
/* Compute the Alpha refinement matrix. */
MergedKVt = BspKnotMergeTwo(KnotVector, Length + Order,
t, n, 0, &LengthKVt);
A = BspKnotEvalAlphaCoef(Order, KnotVector, Length,
MergedKVt, LengthKVt - Order);
RefinedCrv = BspCrvNew(Crv -> Length + n, Order, Crv -> PType);
/* Update the knot vector. */
IritFree((VoidPtr) RefinedCrv -> KnotVector);
RefinedCrv -> KnotVector = MergedKVt;
/* Update the control mesh */
for (j = IsNotRational; j <= MaxCoord; j++) {
CagdRType
*ROnePts = RefinedCrv -> Points[j],
*OnePts = Crv -> Points[j];
for (i = 0; i < RefinedCrv -> Length; i++, ROnePts++)
CAGD_ALPHA_BLEND(A, i, OnePts, Crv -> Length, ROnePts);
}
BspKnotFreeAlphaCoef(A);
}
BspKnotMakeRobustKV(RefinedCrv -> KnotVector,
RefinedCrv -> Order + RefinedCrv -> Length);
if (NewCrv)
CagdCrvFree(Crv);
return RefinedCrv;
}
/*****************************************************************************
* DESCRIPTION: M
* Returns a new curve, identical to the original but with order N. M
* Degree raise is computed by multiplying by a constant 1 curve of order M
* *
* PARAMETERS: M
* Crv: To raise its degree to a NewOrder. M
* NewOrder: NewOrder for Crv. M
* *
* RETURN VALUE: M
* CagdCrvStruct *: A curve of order NewOrder representing the same M
* geometry as Crv. M
* *
* KEYWORDS: M
* BspCrvDegreeRaiseN, degree raising M
*****************************************************************************/
CagdCrvStruct *BspCrvDegreeRaiseN(CagdCrvStruct *Crv, int NewOrder)
{
CagdBType
NewCrv = FALSE;
int i, j, RaisedOrder, Length, KvLen1,
Order = Crv -> Order,
MaxCoord = CAGD_NUM_OF_PT_COORD(Crv -> PType);
CagdCrvStruct *RaisedCrv, *UnitCrv;
CagdRType *Kv;
if (CAGD_IS_PERIODIC_CRV(Crv)) {
NewCrv = TRUE;
Crv = CnvrtPeriodic2FloatCrv(Crv);
}
Length = Crv -> Length;
KvLen1 = Order + Length - 1;
Kv = Crv -> KnotVector;
if (NewOrder < Order) {
CAGD_FATAL_ERROR(CAGD_ERR_WRONG_ORDER);
return NULL;
}
RaisedOrder = NewOrder - Order + 1;
UnitCrv = BspCrvNew(RaisedOrder, RaisedOrder,
CAGD_MAKE_PT_TYPE(FALSE, MaxCoord));
for (i = 0; i < RaisedOrder * 2; i++)
UnitCrv -> KnotVector[i] = i >= RaisedOrder ? Kv[KvLen1] : Kv[0];
for (i = 1; i <= MaxCoord; i++)
for (j = 0; j < RaisedOrder; j++)
UnitCrv -> Points[i][j] = 1.0;
RaisedCrv = BspCrvMult(Crv, UnitCrv);
CagdCrvFree(UnitCrv);
if (NewCrv)
CagdCrvFree(Crv);
return RaisedCrv;
}
/*****************************************************************************
* DESCRIPTION: M
* Returns a new curve, identical to the original but with one degree higher. M
* *
* PARAMETERS: M
* Crv: To raise it degree by one. M
* *
* RETURN VALUE: M
* CagdCrvStruct *: A curve with one degree higher representing the same M
* geometry as Crv. M
* *
* KEYWORDS: M
* BspCrvDegreeRaise, degree raising M
*****************************************************************************/
CagdCrvStruct *BspCrvDegreeRaise(CagdCrvStruct *Crv)
{
CagdBType
NewCrv = FALSE,
IsNotRational = !CAGD_IS_RATIONAL_CRV(Crv);
int i, i2, j, RaisedLen, Length,
Order = Crv -> Order,
MaxCoord = CAGD_NUM_OF_PT_COORD(Crv -> PType);
CagdCrvStruct *RaisedCrv;
if (CAGD_IS_PERIODIC_CRV(Crv)) {
NewCrv = TRUE;
Crv = CnvrtPeriodic2FloatCrv(Crv);
}
Length = Crv -> Length;
if (Order > 2)
return BspCrvDegreeRaiseN(Crv, Order + 1);
/* If curve is linear, degree raising means basically to increase the */
/* knot multiplicity of each segment by one and add a middle point for */
/* each such segment. */
RaisedLen = Length * 2 - 1;
RaisedCrv = BspCrvNew(RaisedLen, Order + 1, Crv -> PType);
/* Update the control polygon; */
for (j = IsNotRational; j <= MaxCoord; j++) /* First point. */
RaisedCrv -> Points[j][0] = Crv -> Points[j][0];
for (i = 1, i2 = 1; i < Length; i++, i2 += 2)
for (j = IsNotRational; j <= MaxCoord; j++) {
RaisedCrv -> Points[j][i2] =
Crv -> Points[j][i-1] * 0.5 + Crv -> Points[j][i] * 0.5;
RaisedCrv -> Points[j][i2 + 1] = Crv -> Points[j][i];
}
/* Update the knot vector. */
for (i = 0; i < 3; i++)
RaisedCrv -> KnotVector[i] = Crv -> KnotVector[0];
for (i = 2, j = 3; i < Length; i++, j += 2)
RaisedCrv -> KnotVector[j] = RaisedCrv -> KnotVector[j + 1] =
Crv -> KnotVector[i];
for (i = j; i < j + 3; i++)
RaisedCrv -> KnotVector[i] = Crv -> KnotVector[Length];
if (NewCrv)
CagdCrvFree(Crv);
return RaisedCrv;
}
/*****************************************************************************
* DESCRIPTION: M
* Returns a unit vector, equal to the tangent to Crv at parameter value t. M
* Algorithm: insert (order - 1) knots and return control polygon tangent. M
* *
* PARAMETERS: M
* Crv: Crv for which to compute a unit tangent. M
* t: The parameter at which to compute the unit tangent. M
* *
* RETURN VALUE: M
* CagdVecStruct *: A pointer to a static vector holding the tangent M
* information. M
* *
* KEYWORDS: M
* BspCrvTangent, tangent M
*****************************************************************************/
CagdVecStruct *BspCrvTangent(CagdCrvStruct *Crv, CagdRType t)
{
static CagdVecStruct P2;
CagdVecStruct P1, *T;
CagdRType TMin, TMax;
CagdCrvStruct
*FCrv = CAGD_IS_PERIODIC_CRV(Crv) ? CnvrtPeriodic2FloatCrv(Crv) : Crv;
int k = FCrv -> Order,
Len = FCrv -> Length,
OpenEnd = BspCrvHasOpenEC(FCrv),
Index = BspKnotLastIndexL(FCrv -> KnotVector, k + Len, t);
CagdPointType
PType = FCrv -> PType;
CagdCrvStruct *RefinedCrv;
CAGD_DOMAIN_GET_AND_VERIFY_CRV(t, FCrv, TMin, TMax);
if (APX_EQ(t, TMin) && OpenEnd) {
/* Use Crv starting tangent direction. */
CagdCoerceToE3(P1.Vec, FCrv -> Points, 0, PType);
CagdCoerceToE3(P2.Vec, FCrv -> Points, 1, PType);
}
else if (APX_EQ(t, TMax) && OpenEnd) {
/* Use Crv ending tangent direction. */
CagdCoerceToE3(P1.Vec, FCrv -> Points, Len - 2, PType);
CagdCoerceToE3(P2.Vec, FCrv -> Points, Len - 1, PType);
}
else {
RefinedCrv = BspCrvKnotInsertNSame(FCrv, t, k - 1);
CagdCoerceToE3(P1.Vec, RefinedCrv -> Points, Index, PType);
CagdCoerceToE3(P2.Vec, RefinedCrv -> Points, Index + 1, PType);
CagdCrvFree(RefinedCrv);
}
CAGD_SUB_VECTOR(P2, P1);
if (CAGD_LEN_VECTOR(P2) < IRIT_EPSILON) {
if (AttrGetIntAttrib(Crv -> Attr, "_tan") != TRUE) {
/* Try to move a little. This location has zero speed. However, */
/* do it only once since we can be here forever. The "_tan" */
/* attribute guarantee we will try to move EPSILON only once. */
AttrSetIntAttrib(&Crv -> Attr, "_tan", TRUE);
T = BspCrvTangent(Crv, t - TMin < TMax - t ? t + EPSILON
: t - EPSILON);
AttrFreeOneAttribute(&Crv -> Attr, "_tan");
if (FCrv != Crv)
CagdCrvFree(FCrv);
return T;
}
else {
/* A zero length vector signals failure to compute tangent. */
if (FCrv != Crv)
CagdCrvFree(FCrv);
return &P2;
}
}
else {
CAGD_NORMALIZE_VECTOR(P2); /* Normalize the vector. */
if (FCrv != Crv)
CagdCrvFree(FCrv);
return &P2;
}
}
/*****************************************************************************
* DESCRIPTION: M
* Returns a unit vector, equal to the binormal to Crv at parameter value t. M
* Algorithm: insert (order - 1) knots and using 3 consecutive control M
* points at the refined location (p1, p2, p3), compute to binormal to be the M
* cross product of the two vectors (p1 - p2) and (p2 - p3). M
* Since a curve may have not BiNormal at inflection points or if the 3 M
* points are colinear, NULL will be returned at such cases. M
* *
* PARAMETERS: M
* Crv: Crv for which to compute a unit binormal. M
* t: The parameter at which to compute the unit binormal. M
* *
* RETURN VALUE: M
* CagdVecStruct *: A pointer to a static vector holding the binormal M
* information. M
* *
* KEYWORDS: M
* BspCrvBiNormal, binormal M
*****************************************************************************/
CagdVecStruct *BspCrvBiNormal(CagdCrvStruct *Crv, CagdRType t)
{
static CagdVecStruct P3;
CagdVecStruct P1, P2;
CagdRType TMin, TMax;
CagdCrvStruct
*FCrv = CAGD_IS_PERIODIC_CRV(Crv) ? CnvrtPeriodic2FloatCrv(Crv) : Crv;
int k = FCrv -> Order,
Len = FCrv -> Length,
OpenEnd = BspCrvHasOpenEC(FCrv),
Index = BspKnotLastIndexL(FCrv -> KnotVector, k + Len, t);
CagdPointType
PType = FCrv -> PType;
CagdCrvStruct *RefinedCrv;
CAGD_DOMAIN_GET_AND_VERIFY_CRV(t, FCrv, TMin, TMax);
/* Can not compute for linear curves. */
if (k <= 2)
return NULL;
/* For planar curves, B is trivially the Z axis. */
if (CAGD_NUM_OF_PT_COORD(FCrv -> PType) == 2) {
P3.Vec[0] = P3.Vec[1] = 0.0;
P3.Vec[2] = 1.0;
return &P3;
}
if (APX_EQ(t, TMin) && OpenEnd) {
/* Use Crv starting tangent direction. */
CagdCoerceToE3(P1.Vec, FCrv -> Points, 0, PType);
CagdCoerceToE3(P2.Vec, FCrv -> Points, 1, PType);
CagdCoerceToE3(P3.Vec, FCrv -> Points, 2, PType);
}
else if (APX_EQ(t, TMax) && OpenEnd) {
/* Use Crv ending tangent direction. */
CagdCoerceToE3(P1.Vec, FCrv -> Points, Len - 3, PType);
CagdCoerceToE3(P2.Vec, FCrv -> Points, Len - 2, PType);
CagdCoerceToE3(P3.Vec, FCrv -> Points, Len - 1, PType);
}
else {
RefinedCrv = BspCrvKnotInsertNSame(FCrv, t, k - 1);
CagdCoerceToE3(P1.Vec, RefinedCrv -> Points, Index, PType);
CagdCoerceToE3(P2.Vec, RefinedCrv -> Points, Index + 1, PType);
CagdCoerceToE3(P3.Vec, RefinedCrv -> Points, Index + 2, PType);
CagdCrvFree(RefinedCrv);
}
CAGD_SUB_VECTOR(P1, P2);
CAGD_SUB_VECTOR(P2, P3);
CROSS_PROD(P3.Vec, P1.Vec, P2.Vec);
if (FCrv != Crv)
CagdCrvFree(FCrv);
if ((t = CAGD_LEN_VECTOR(P3)) < IRIT_EPSILON)
return NULL;
else
CAGD_DIV_VECTOR(P3, t); /* Normalize the vector. */
return &P3;
}
/*****************************************************************************
* DESCRIPTION: M
* Returns a unit vector, equal to the normal of Crv at parameter value t. M
* Algorithm: returns the cross product of the curve tangent and binormal. M
* *
* PARAMETERS: M
* Crv: Crv for which to compute a unit normal. M
* t: The parameter at which to compute the unit normal. M
* *
* RETURN VALUE: M
* CagdVecStruct *: A pointer to a static vector holding the normal M
* information. M
* *
* KEYWORDS: M
* BspCrvNoraml, normal M
*****************************************************************************/
CagdVecStruct *BspCrvNormal(CagdCrvStruct *Crv, CagdRType t)
{
static CagdVecStruct N, *T, *B;
T = BspCrvTangent(Crv, t);
B = BspCrvBiNormal(Crv, t);
if (T == NULL || B == NULL)
return NULL;
CROSS_PROD(N.Vec, T -> Vec, B -> Vec);
CAGD_NORMALIZE_VECTOR(N); /* Normalize the vector. */
return &N;
}
/*****************************************************************************
* DESCRIPTION: M
* Returns a new curve, equal to the given curve, differentiated once. M
* Let old control polygon be P(i), i = 0 to k-1, and Q(i) be new one then: M
* Q(i) = (k - 1) * (P(i+1) - P(i)) / (Kv(i + k) - Kv(i + 1)), i = 0 to k-2. V
* *
* PARAMETERS: M
* Crv: To differentiate. M
* *
* RETURN VALUE: M
* CagdCrvStruct *: Differentiated curve. M
* *
* KEYWORDS: M
* BspCrvDerive, derivatives M
*****************************************************************************/
CagdCrvStruct *BspCrvDerive(CagdCrvStruct *Crv)
{
CagdBType
NewCrv = FALSE,
IsNotRational = !CAGD_IS_RATIONAL_CRV(Crv);
int i, j, Len,
k = Crv -> Order,
MaxCoord = CAGD_NUM_OF_PT_COORD(Crv -> PType);
CagdRType *Kv;
CagdCrvStruct *DerivedCrv;
if (CAGD_IS_PERIODIC_CRV(Crv)) {
NewCrv = TRUE;
Crv = CnvrtPeriodic2FloatCrv(Crv);
}
if (!IsNotRational) {
DerivedCrv = BspCrvDeriveRational(Crv);
if (NewCrv)
CagdCrvFree(Crv);
return DerivedCrv;
}
Len = Crv -> Length;
Kv = Crv -> KnotVector;
DerivedCrv = BspCrvNew(MAX(Len - 1, 1), MAX(k - 1, 1), Crv -> PType);
if (k >= 2) {
for (i = 0; i < Len - 1; i++) {
CagdRType
Denom = Kv[i + k] - Kv[i + 1];
for (j = IsNotRational; j <= MaxCoord; j++)
DerivedCrv -> Points[j][i] = (k - 1) *
(Crv -> Points[j][i + 1] - Crv -> Points[j][i]) / Denom;
}
}
else {
for (i = 0; i < MAX(Len - 1, 1); i++)
for (j = IsNotRational; j <= MaxCoord; j++)
DerivedCrv -> Points[j][i] = 0.0;
}
CAGD_GEN_COPY(DerivedCrv -> KnotVector,
&Crv -> KnotVector[k < 2 ? 0 : 1],
sizeof(CagdRType) * (MAX(k - 1, 1) + MAX(Len - 1, 1)));
if (NewCrv)
CagdCrvFree(Crv);
return DerivedCrv;
}
/*****************************************************************************
* DESCRIPTION: M
* Returns a new Bspline curve, equal to the integral of the given Bspline M
* crv. M
* The given Bspline curve should be nonrational. M
* V
* l l l l+1 V
* / /- - / - P - V
* | | \ n \ | n \ i \ n+1 V
* | C(t) = | / P B (t) = / P | B (t) = / ----- / ( t - t ) B (t) = V
* / / - i i - i / i - n + 1 - j+n j j V
* i=0 i=0 i=0 j=i+1 V
* V
* l+1 j-1 V
* - - V
* 1 \ \ n+1 V
* = ----- / / P ( t - t ) B (t) V
* n + 1 - - i j+n j j V
* j=1 i=0 V
* M
* *
* PARAMETERS: M
* Crv: Curve to integrate. M
* *
* RETURN VALUE: M
* CagdCrvStruct *: Integrated curve. M
* *
* KEYWORDS: M
* BspCrvIntegrate, integrals M
*****************************************************************************/
CagdCrvStruct *BspCrvIntegrate(CagdCrvStruct *Crv)
{
CagdBType
NewCrv = FALSE;
int i, j, k, Len,
n = Crv -> Order,
MaxCoord = CAGD_NUM_OF_PT_COORD(Crv -> PType);
CagdCrvStruct *IntCrv;
CagdRType *Kv;
if (CAGD_IS_PERIODIC_CRV(Crv)) {
NewCrv = TRUE;
Crv = CnvrtPeriodic2FloatCrv(Crv);
}
if (CAGD_IS_RATIONAL_CRV(Crv))
CAGD_FATAL_ERROR(CAGD_ERR_RATIONAL_NO_SUPPORT);
Len = Crv -> Length;
Kv = Crv -> KnotVector;
IntCrv = BspCrvNew(Len + 1, n + 1, Crv -> PType);
/* Copy the knot vector and duplicate the two end knots. */
CAGD_GEN_COPY(&IntCrv -> KnotVector[1], Kv, sizeof(CagdRType) * (Len + n));
IntCrv -> KnotVector[0] = Kv[0];
IntCrv -> KnotVector[Len + n + 1] = Kv[Len + n - 1];
Kv = IntCrv -> KnotVector;
for (k = 1; k <= MaxCoord; k++) {
CagdRType
*Points = Crv -> Points[k],
*IntPoints = IntCrv -> Points[k];
for (j = 0; j < Len + 1; j++) {
IntPoints[j] = 0.0;
for (i = 0; i < j; i++)
IntPoints[j] += Points[i] * (Kv[i + n + 1] - Kv[i + 1]);
IntPoints[j] /= n;
}
}
if (NewCrv)
CagdCrvFree(Crv);
return IntCrv;
}
/*****************************************************************************
* DESCRIPTION: M
* Returns a new linear Bspline curve constructed from the given polyline. M
* *
* PARAMETERS: M
* Poly: To convert to a linear bspline curve. M
* *
* RETURN VALUE: M
* CagdCrvStruct *: A linear Bspline curve representing Poly. M
* *
* KEYWORDS: M
* CnvrtPolyline2LinBsplineCrv, linear curves, conversion M
*****************************************************************************/
CagdCrvStruct *CnvrtPolyline2LinBsplineCrv(CagdPolylineStruct *Poly)
{
int i,
Length = Poly -> Length;
CagdCrvStruct
*Crv = BspCrvNew(Length, 2, CAGD_PT_E3_TYPE);
CagdRType
**Points = Crv -> Points;
CagdPolylnStruct
*Pts = Poly -> Polyline;
BspKnotUniformOpen(Length, 2, Crv -> KnotVector);
for (i = 0; i < Length; i++, Pts++) {
Points[1][i] = Pts -> Pt[0];
Points[2][i] = Pts -> Pt[1];
Points[3][i] = Pts -> Pt[2];
}
return Crv;
}
/*****************************************************************************
* DESCRIPTION: M
* Converts a Bspline curve to a Bspline curve with floating end conditions. M
* *
* PARAMETERS: M
* Crv: Bspline curve to convert to floating end conditions. Assume M
* Crv is either periodic or has floating end condition. M
* *
* RETURN VALUE: M
* CagdCrvStruct *: A Bspline curve with floating end conditions, M
* representing the same geometry as Crv. M
* *
* KEYWORDS: M
* CnvrtPeriodic2FloatCrv, conversion M
*****************************************************************************/
CagdCrvStruct *CnvrtPeriodic2FloatCrv(CagdCrvStruct *Crv)
{
int i,
Order = Crv -> Order,
Length = Crv -> Length,
MaxAxis = CAGD_NUM_OF_PT_COORD(Crv -> PType);
CagdCrvStruct *NewCrv;
if (!CAGD_IS_PERIODIC_CRV(Crv)) {
CAGD_FATAL_ERROR(CAGD_ERR_PERIODIC_EXPECTED);
return NULL;
}
NewCrv = BspCrvNew(Length + Order - 1, Order, Crv -> PType);
NewCrv -> KnotVector = BspKnotCopy(Crv -> KnotVector,
Length + Order + Order - 1);
for (i = !CAGD_IS_RATIONAL_PT(Crv -> PType); i <= MaxAxis; i++) {
NewCrv -> Points[i] = (CagdRType *) IritMalloc(sizeof(CagdRType) *
(Length + Order + Order - 1));
CAGD_GEN_COPY(NewCrv -> Points[i], Crv -> Points[i],
sizeof(CagdRType) * Length);
CAGD_GEN_COPY(&NewCrv -> Points[i][Length], Crv -> Points[i],
sizeof(CagdRType) * (Order - 1));
}
for (i = MaxAxis + 1; i <= CAGD_MAX_PT_COORD; i++)
NewCrv -> Points[i] = NULL;
return NewCrv;
}
/*****************************************************************************
* DESCRIPTION: M
* Converts a Bspline curve to a Bspline curve with open end conditions. M
* *
* PARAMETERS: M
* Crv: Bspline curve to convert to open end conditions. M
* *
* RETURN VALUE: M
* CagdCrvStruct *: A Bspline curve with open end conditions, M
* representing the same geometry as Crv. M
* *
* KEYWORDS: M
* CnvrtPeriodic2FloatCrv, conversion M
*****************************************************************************/
CagdCrvStruct *CnvrtFloat2OpenCrv(CagdCrvStruct *Crv)
{
CagdRType TMin, TMax;
if (!CAGD_IS_BSPLINE_CRV(Crv)) {
CAGD_FATAL_ERROR(CAGD_ERR_BSP_CRV_EXPECT);
return NULL;
}
CagdCrvDomain(Crv, &TMin, &TMax);
return CagdCrvRegionFromCrv(Crv, TMin, TMax);
}